﻿using System;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using MovieViewerLib;
using System.Reflection;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
//using IMDb_Scraper;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Web;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;

namespace MovieViewerUI
{
    public partial class DemoForm : Form
    {
        private string cacheFilePath = null;
        private string appRoot = null;
        private string thumbnailPath = null;
        private MovieCollection movies = null;
        private ImdbHelper imdb = null;
        //#region A Custom Renderer for Demonstrating the Control
        ///// <summary>
        ///// A renderer that displays useful information
        ///// when the control is empty.
        ///// </summary>
        //private class DemoRenderer : ImageListView.ImageListViewRenderer
        //{
        //    string[] infoTexts = new string[] { 
        //        "Start by adding location of your movies",
        //        "You can switch between Thumbnails, Gallery, Pane and Details view modes.",
        //        "In Details mode, ImageListView displays image properties in columns.",
        //        "The appearance of ImageListView can be customized to a great extent.\r\nTry selecting a different renderer from the drop down.",
        //        "Size of generated thumbnails can be customized.\r\nImageListView will try to extract embedded Exif thumbnails if possible.",
        //    };

        //    int[] infoLocations = new int[]{
        //        23,
        //        190,
        //        244,
        //        360,
        //        490,
        //    };

        //    int current;
        //    private System.Windows.Forms.Timer infoTimer;

        //    public DemoRenderer()
        //    {
        //        current = 0;
        //        infoTimer = new System.Windows.Forms.Timer();
        //        infoTimer.Interval = 5000;
        //        infoTimer.Tick += new EventHandler(infoTimer_Tick);
        //        infoTimer.Enabled = true;
        //    }

        //    void infoTimer_Tick(object sender, EventArgs e)
        //    {
        //        current++;
        //        if (current == infoTexts.Length)
        //            current = 0;

        //        ImageListView.Refresh();
        //    }

        //    public override void Dispose()
        //    {
        //        infoTimer.Dispose();
        //        base.Dispose();
        //    }

        //    /// <summary>
        //    /// Initializes the System.Drawing.Graphics used to draw
        //    /// control elements.
        //    /// </summary>
        //    /// <param name="g">The System.Drawing.Graphics to draw on.</param>
        //    public override void InitializeGraphics(Graphics g)
        //    {
        //        base.InitializeGraphics(g);
        //        g.SmoothingMode = SmoothingMode.HighQuality;
        //    }

        //    /// <summary>
        //    /// Draws an overlay image over the client area.
        //    /// </summary>
        //    /// <param name="g">The System.Drawing.Graphics to draw on.</param>
        //    /// <param name="bounds">The bounding rectangle of the client area.</param>
        //    public override void DrawOverlay(Graphics g, Rectangle bounds)
        //    {
        //        if (ImageListView.Items.Count != 0)
        //        {
        //            infoTimer.Enabled = false;
        //            return;
        //        }

        //        if (!infoTimer.Enabled)
        //        {
        //            current = 0;
        //            infoTimer.Enabled = true;
        //        }

        //        DrawToolTip(g, infoLocations[current], infoTexts[current]);
        //    }

        //    /// <summary>
        //    /// Draws a tooltip.
        //    /// </summary>
        //    private void DrawToolTip(Graphics g, int x, string s)
        //    {
        //        bool onLeft = (x < ImageListView.ClientRectangle.Width / 2);
        //        int width = 200;
        //        Size sz = Size.Round(g.MeasureString(s, ImageListView.Font, width));
        //        sz.Width += 20;
        //        sz.Height += 10;
        //        int y = 12;

        //        int arrowOffset = 15;
        //        if (!onLeft) arrowOffset = sz.Width - 30;
        //        if (!onLeft) x -= sz.Width - 45;

        //        int fillet = 10;
        //        if (fillet > sz.Height / 2) fillet = sz.Height / 2;
        //        int shadow = 3;

        //        using (GraphicsPath path = new GraphicsPath())
        //        {
        //            path.AddLine(x - 20 + arrowOffset, y, x - 15 + arrowOffset, y - 10);
        //            path.AddLine(x - 15 + arrowOffset, y - 10, x - 10 + arrowOffset, y);
        //            path.AddLine(x - 10 + arrowOffset, y, x + sz.Width - 20 - fillet, y);
        //            path.AddArc(x + sz.Width - 20 - 2 * fillet, y, 2 * fillet, 2 * fillet, 270.0f, 90.0f);
        //            path.AddLine(x + sz.Width - 20, y + fillet, x + sz.Width - 20, y + sz.Height - fillet);
        //            path.AddArc(x + sz.Width - 20 - 2 * fillet, y + sz.Height - 2 * fillet, 2 * fillet, 2 * fillet, 0.0f, 90.0f);
        //            path.AddLine(x + sz.Width - 20 - fillet, y + sz.Height, x - 20 + fillet, y + sz.Height);
        //            path.AddArc(x - 20, y + sz.Height - 2 * fillet, 2 * fillet, 2 * fillet, 90.0f, 90.0f);
        //            path.AddLine(x - 20, y + sz.Height - fillet, x - 20, y + fillet);
        //            path.AddArc(x - 20, y, 2 * fillet, 2 * fillet, 180.0f, 90.0f);
        //            path.AddLine(x - 20 + fillet, y, x - 20 + arrowOffset, y);
        //            path.CloseFigure();

        //            path.Transform(new Matrix(1, 0, 0, 1, shadow, shadow));
        //            using (Brush b = new SolidBrush(Color.FromArgb(128, Color.Black)))
        //            {
        //                g.FillPath(b, path);
        //            }
        //            path.Transform(new Matrix(1, 0, 0, 1, -shadow, -shadow));

        //            using (Brush b = new LinearGradientBrush(path.GetBounds(), Color.BlanchedAlmond, Color.White, LinearGradientMode.ForwardDiagonal))
        //            {
        //                g.FillPath(b, path);
        //            }
        //            using (Pen p = new Pen(SystemColors.InfoText))
        //            {
        //                g.DrawPath(p, path);
        //            }
        //            using (Brush b = new SolidBrush(SystemColors.InfoText))
        //            {
        //                g.DrawString(infoTexts[current], ImageListView.Font, b, new Rectangle(x - 20 + 10, y + 5, sz.Width - 16, sz.Height - 10));
        //            }
        //        }
        //    }
        //}
        //#endregion

        #region Constructor
        public DemoForm()
        {
            InitializeComponent();

            Application.Idle += new EventHandler(Application_Idle);

            // Populate renderer dropdown
            Assembly assembly = Assembly.GetAssembly(typeof(MovieListView));
            int i = 0;
            foreach (Type t in assembly.GetTypes())
            {
                if (t.BaseType == typeof(MovieViewerLib.MovieListView.MovieListViewRenderer))
                {
                    renderertoolStripComboBox.Items.Add(new RendererItem(t));
                    if (t.Name == "TilesRenderer")
                        renderertoolStripComboBox.SelectedIndex = i;
                    i++;
                }
            }
            movieListView1.SetRenderer(new MovieViewerLib.MovieListViewRenderers.TilesRenderer());
            imdb = new ImdbHelper(movieListView1);
        }

        private void Form1_Load(object sender, System.EventArgs e)
        {
            MovieListView.CheckForIllegalCrossThreadCalls = false;
            appRoot = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
            cacheFilePath = string.Format(@"{0}\Movies.xml", appRoot);
        }

        protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Return:
                    this.toolStripButton1.PerformClick();
                    break;

                default:
                    return base.ProcessCmdKey(ref msg, keyData);
            }

            return true;
        }

        private void Search()
        {
            Stopwatch sw = new Stopwatch();
            movieListView1.Items.Clear();
            movieListView1.AllItems.Clear();
            sw.Restart();
            List<string> exclusionList = new List<string>();
            int sz = 0;
            if (!int.TryParse("550", out sz))
                sz = 600;

            ImdbHelper.movies = ReadCache();
            var extList = new List<string>();
            extList.Add("avi");
            extList.Add("mkv");
            extList.Add("mp4");
            movieListView1.Refresh();
            movieListView1.ResumeLayout();
            ParallelOptions po = new ParallelOptions();
            po.MaxDegreeOfParallelism = 8;
            int count = 0;
            Parallel.ForEach(SafeFileEnumerator.EnumerateFiles(toolStripTextBox1.Text,
                SearchOption.AllDirectories, extList, exclusionList, sz), po, file =>
                {
                    Interlocked.Increment(ref count);
                    ProcessFile(file);
                });
            sw.Stop();
            UpdateStatus(string.Format("{0} items. Time taken: {1}s", movieListView1.Items.Count, Math.Ceiling(sw.Elapsed.TotalSeconds)));
            using (var sw1 = new StreamWriter(new FileStream("ErrorLog.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite)))
            {
                sw1.WriteLine(string.Format("Actual files Count: {0}", count));
                sw1.WriteLine(string.Format("Found in cache Count: {0}", Utility.foundCounter));
                sw1.WriteLine(string.Format("Not Found in cache Count: {0}", Utility.NotFoundCounter));
                sw1.WriteLine(string.Format("Processed Count: {0}", Utility.counter));
            }
            imdb.UpdateCache();
            
        }
        private void ProcessFile(string file)
        {
            try
            {
                string matchingMovieName = GetMatch(Path.GetFileNameWithoutExtension(file));
                imdb.GetMovie(null, file, matchingMovieName);
            }
            catch (Exception ex)
            {
                Utility.Log(string.Format("Error: {0}. {1}", file, ex.Message + ex.StackTrace));
            }
        }

        private string GetMatch(string movieName)
        {
            movieName = movieName.Replace(".", " ");
            int yearIndex = -1;
            Match m = Regex.Match(movieName, @"^(.+)\s(19|20)\d{2}");
            if (m.Success)
                yearIndex = m.Value.Length - 4;
            int minIndex = int.MaxValue;
            bool found = false;
            int[] indexes = { yearIndex, movieName.IndexOf('['), movieName.IndexOf('('), 
                                movieName.IndexOf('-'), movieName.IndexOf("720p"), movieName.IndexOf("1080p") };
            foreach (var item in indexes)
            {
                if (item >= 0 && item <= minIndex)
                {
                    found = true;
                    minIndex = item;
                }
            }
            if (found)
                movieName = movieName.Substring(0, minIndex);
            return movieName.Trim();
        }

        private MovieCollection ReadCache()
        {
            movies = new MovieCollection() { Movie = new List<Movie>() };
            try
            {
                
                if (File.Exists(cacheFilePath))
                {
                    StreamReader reader = new StreamReader(cacheFilePath);
                    XmlSerializer serializer = new XmlSerializer(typeof(MovieCollection));
                    movies = (MovieCollection)serializer.Deserialize(reader);
                    reader.Close();
                }
            }
            catch (Exception ex)
            {
                string s = ex.Message;
            }
            return movies;
        }
        #endregion

        

        #region Refresh UI Cues
        void Application_Idle(object sender, EventArgs e)
        {
            // Refresh UI cues
            removeAllToolStripButton.Enabled = true;// (imageListView1.Items.Count > 0);

            thumbnailsToolStripButton.Checked = (movieListView1.View == MovieViewerLib.View.Thumbnails);
            detailsToolStripButton.Checked = (movieListView1.View == MovieViewerLib.View.Details);
            galleryToolStripButton.Checked = (movieListView1.View == MovieViewerLib.View.Gallery);
            paneToolStripButton.Checked = (movieListView1.View == MovieViewerLib.View.Pane);

            clearCacheToolStripButton.Enabled = (movieListView1.Items.Count > 0);

            x48ToolStripMenuItem.Checked = (movieListView1.ThumbnailSize == new Size(48, 48));
            x96ToolStripMenuItem.Checked = (movieListView1.ThumbnailSize == new Size(96, 96));
            x120ToolStripMenuItem.Checked = (movieListView1.ThumbnailSize == new Size(120, 120));
            x150ToolStripMenuItem.Checked = (movieListView1.ThumbnailSize == new Size(150, 150));
            x200ToolStripMenuItem.Checked = (movieListView1.ThumbnailSize == new Size(200, 200));
        }
        #endregion

        #region Add/Remove Items
        private void addToolStripButton_Click(object sender, EventArgs e)
        {
        }

        private void removeToolStripButton_Click(object sender, EventArgs e)
        {
            // Suspend the layout logic while we are removing items.
            // Otherwise the control will be refreshed after each item
            // is removed.
            movieListView1.SuspendLayout();

            // Remove selected items
            foreach (var item in movieListView1.SelectedItems)
                movieListView1.Items.Remove(item);

            // Resume layout logic.
            movieListView1.ResumeLayout(true);
        }

        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            removeToolStripButton_Click(sender, e);
        }

        private void removeAllToolStripButton_Click(object sender, EventArgs e)
        {
            movieListView1.Items.Clear();
        }
        #endregion

        #region Switch Renderers
        private struct RendererItem
        {
            public Type Type;

            public override string ToString()
            {
                return Type.Name;
            }

            public RendererItem(Type type)
            {
                Type = type;
            }
        }

        private void renderertoolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetRenderer();
        }

        private void SetRenderer()
        {
            // Change the renderer
            Assembly assembly = Assembly.GetAssembly(typeof(MovieListView));
            RendererItem item = (RendererItem)renderertoolStripComboBox.SelectedItem;
            MovieListView.MovieListViewRenderer renderer = assembly.CreateInstance(item.Type.FullName) as MovieListView.MovieListViewRenderer;
            movieListView1.SetRenderer(renderer);
            movieListView1.Focus();
        }
        #endregion

        #region Switch View Modes
        private void detailsToolStripButton_Click(object sender, EventArgs e)
        {
            movieListView1.View = MovieViewerLib.View.Details;
        }

        private void thumbnailsToolStripButton_Click(object sender, EventArgs e)
        {
            movieListView1.View = MovieViewerLib.View.Thumbnails;
        }

        private void galleryToolStripButton_Click(object sender, EventArgs e)
        {
            movieListView1.View = MovieViewerLib.View.Gallery;
        }

        private void paneToolStripButton_Click(object sender, EventArgs e)
        {
            movieListView1.View = MovieViewerLib.View.Pane;
        }
        #endregion

        #region Update Status Bar
        private void imageListView1_ThumbnailCached(object sender, ThumbnailCachedEventArgs e)
        {
        }

        private void imageListView1_SelectionChanged(object sender, EventArgs e)
        {
            UpdateStatus();
        }

        private void timerStatus_Tick(object sender, EventArgs e)
        {
            UpdateStatus();
            timerStatus.Enabled = false;
        }

        private void UpdateStatus(string text)
        {
            toolStripStatusLabel.Text = text;
        }

        private void UpdateStatus()
        {
            if (movieListView1.Items.Count == 0)
                UpdateStatus("Ready");
            else
                UpdateStatus(string.Format("{0} items", movieListView1.Items.Count));
        }
        #endregion

        #region Modify Column Headers
        private void columnsToolStripButton_Click(object sender, EventArgs e)
        {
            ChooseColumns form = new ChooseColumns();
            form.imageListView = movieListView1;
            form.ShowDialog();
        }
        #endregion

        #region Change Thumbnail Size
        private void x48ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            movieListView1.ThumbnailSize = new Size(48, 48);
        }

        private void x96ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            movieListView1.ThumbnailSize = new Size(96, 96);
        }

        private void x120ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            movieListView1.ThumbnailSize = new Size(120, 120);
        }

        private void x150ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            movieListView1.ThumbnailSize = new Size(150, 150);
        }

        private void x200ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            movieListView1.ThumbnailSize = new Size(200, 200);
        }

        private void clearCacheToolStripButton_Click(object sender, EventArgs e)
        {
            movieListView1.ClearThumbnailCache();
        }
        #endregion        

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            UpdateStatus("Searching...");
            movieListView1.StartRefresh = true;
            Task.Run(() => Search());
            movieListView1.StartRefresh = false;
        }

        private void toolStriptextBox2Text_Change(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                try
                {
                    movieListView1.Items.Clear();
                    Parallel.For(0, movieListView1.AllItems.Count, (i) =>
                    {
                        double rat = 0.0;
                        double itemrat = 0.0;
                        var item = movieListView1.AllItems[i];
                        if (string.IsNullOrWhiteSpace(toolStripTextBox2.Text) ||
                            item.MovieName != null && item.MovieName.ToLower().Contains(toolStripTextBox2.Text.ToLower()) ||
                            item.Genre != null && item.Genre.ToLower().Contains(toolStripTextBox2.Text.ToLower()) ||
                            item.Year != null && item.Year.ToLower().Contains(toolStripTextBox2.Text.ToLower()))// ||
                            movieListView1.SetVisible(i, true);
                        else
                            movieListView1.SetVisible(i, false);
                    });
                }
                catch (Exception ex)
                {

                }
            });
        }

        private void toolStripTextBox2_Click(object sender, EventArgs e)
        {
            if (toolStripTextBox2.Text == "Search movie")
                toolStripTextBox2.Text = "";
        }

        private void toolStripTextBox2_Leave(object sender, EventArgs e)
        {
            if (toolStripTextBox2.Text == "")
                toolStripTextBox2.Text = "Search movie";
        }        
    }
}
